/*!
 * \file dmxcon/stage.h
 * \author Christian Spoo
 * \date 01.08.2010
 *
 * \brief DMXcon stage management
 * 
 *  DMXcon introduces the stage concept to incorporate the ability to manage multiple DMX512 universes.
 *  A stage contains a virtual DMX address space which is divided into several DMX universes that are
 *  each controlled by a DMX host adapter.
 *
 *  These universes do not necessarily need to be 512 addresses long. That way you can use more universes
 *  to reduce the time to change a channel value on your DMX line.
 *
 *  For example, you can control 1024 DMX channels with e.g. two adapters with 512 channels each or
 *  16 adapters that only need to output 64 channels per adapter. Of course, the latter example allows for
 *  more flexibility at the cost of installing 16 DMX lines instead of two.
 */

#ifndef __DMXCON__STAGE_H__
#define __DMXCON__STAGE_H__

#include <dmxcon/device.h>
#include <dmxcon/fixture.h>

#ifdef __cplusplus
extern "C" {
#endif

/*! \brief Entry structure for the linked device list
 */
struct devlist_entry_t {
  /*! \brief start address of the device
   */ 
  unsigned int start_addr;

  /*! \brief end address of the device
   */
  unsigned int end_addr;

  /*! \brief Pointer to device descriptor
   */
  struct device_t *device;

  /*! \brief List pointer to next element in list
   */
  struct devlist_entry_t *next;
};

/*! \brief Entry structure for the linked fixture list
 */
struct fixturelist_entry_t {
  /*! \brief fixture pointer
   */
  struct fixture_t *fixture;

  /*! \brief List pointer to next element in list
   */
  struct fixturelist_entry_t *next;
};

/*! \brief Stage structure
 *
 *  This structure contains all information about the stage, such as the device list. 
 */
struct stage_t {
  /*! \brief Pointer to the first element in the device list
   */
  struct devlist_entry_t *devices;

  /*! \brief Pointer to the first element in the fixture list
   */
  struct fixturelist_entry_t *fixtures;
};

/*! \brief Creates a new stage
 */
struct stage_t *stage_create(void);

/*! \brief Destroys the stage
 *  @param stage  Stage to be destroyed
 *
 *  stage_destroy() will destroy the stage and free all registered devices in it.
 */
int stage_destroy(struct stage_t *stage);

/*! \brief Registers a new device with the stage.
 *  @param stage       Stage to register device with
 *  @param device      Device to register
 *  @param start_addr  Start address the device will be mapped in
 *  @param end_addr    End address the device will occupate in virtual address space
 *
 *  Note that the stage will take the ownership of the device. Do not manually free the device descriptor after registering it.
 */
int stage_register_device(struct stage_t *stage, struct device_t *device, unsigned int start_addr, unsigned int end_addr);

/*! \brief Unregisters a device.
 *  @param stage       Stage to unregister device from
 *  @param device      Device to unregister
 *
 *  After unregistering a device the calling process is responsible for freeing the used memory for the device descriptor.
 */
int stage_unregister_device(struct stage_t *stage, struct device_t *device);

/*! \brief Set a channel in the stage
 *  @param stage       Stage to set channel in
 *  @param addr        Channel address
 *  @param value       New channel value
 */
int stage_set_channel(struct stage_t *stage, unsigned int addr, unsigned char value);

/*! \brief Sets several channels in the stage.
 *  @param stage       Stage to set channels in
 *  @param start_addr  Address to start changing channels from
 *  @param data        Data array with channel values
 *  @param len         Length of the data array
 *
 *  stage_set_channels() will set the specified channel range to the values in the array parameter. The addresses can span
 *  multiple host devices.
 */
int stage_set_channels(struct stage_t *stage, unsigned int start_addr, unsigned char *data, unsigned int len);

/*! \brief Returns the current value of the DMX channel.
 *  @param stage       Stage to read channel from
 *  @param addr        Channel address
 *
 *  Note that depending on the device driver implementation the returned value might not represent the actual state of the
 *  channel on the DMX line, if you didn't call stage_refresh_devices() in the meantime.
 */ 
unsigned char stage_get_channel(struct stage_t *stage, unsigned int addr);

/*! \brief Reads values of the DMX channel.
 *  @param stage       Stage to read channels from
 *  @param start_addr  Address to start reading from
 *  @param data        Data array to write to
 *  @param len         Length of the data array
 *
 *  Note that depending on the device driver implementation the returned values might not represent the actual state of the
 *  channels on the DMX line, if you didn't call stage_refresh_devices() in the meantime.
 */ 
int stage_get_channels(struct stage_t *stage, unsigned int start_addr, unsigned char *data, unsigned int len);

/*! \brief Refreshes all devices in the stage
 *  @param stage       Stage to refresh devices in
 */
int stage_refresh_devices(struct stage_t *stage);

/*! \brief Registers a new fixture with the stage
 *  @param stage       Stage to register fixture with
 *  @param fixture     Fixture to register
 */
int stage_register_fixture(struct stage_t *stage, struct fixture_t *fixture);

/*! \brief Unregister fixture
 *  @param stage       Stage to unregister fixture from
 *  @param fixture     Fixture to unregister
 */
int stage_unregister_fixture(struct stage_t *stage, struct fixture_t *fixture);

#ifdef __cplusplus
}
#endif

#endif

